home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 July: Mac OS SDK / Dev.CD Jul 00 SDK2.toast / Development Kits / Hardware / Mac OS USB DDK / Mac OS USB DDK 1.4.1 / Examples / USBSampleStorageDriver / StorageClassDriver / StorageClassCBIProtocol.c < prev    next >
Encoding:
Text File  |  2000-04-25  |  15.3 KB  |  565 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        StorageClassCBIProtocol.c
  3.  
  4.     Contains:    All code specific to handling the Command/Bulk/Interrupt Protocol
  5.  
  6.     Version:    1.3
  7.  
  8.     Copyright:    © 1998-1999 by Apple Computer, Inc., all rights reserved.
  9. */
  10. // System Headers
  11. #include <DriverServices.h>
  12.  
  13. // Class Driver Headers
  14. #include "StorageClassCBIProtocol.h"
  15.  
  16. // ******************** CBI Protocol Functions **************************
  17. // CBI State Machine States
  18. enum
  19. {
  20.     kCBIExecuteCommand    = 1,            // Begin execution of user command
  21.     kCBIExecuteCommandCompletion,        // Complete the user command
  22.     kCBIBulkIOComplete,                    // Complete the bulk I/O
  23.     kCBIReadInterruptComplete,
  24.     kCBIGetStatusControlEndpointComplete,
  25.     kCBIClearControlEndpointComplete,
  26.     kCBIGetStatusBulkEndpointComplete,
  27.     kCBIClearBulkEndpointComplete
  28. };
  29.  
  30. // Structure for the global PB's
  31. struct StorageClassTransactionPB 
  32. {
  33.     USBPB                            usbPB;
  34.     UInt8                            cdb[kUSBStorageMaxCDBSize];
  35.     UInt8                            GetStatusBuffer[2];    // 2 bytes as specified in the USB spec
  36.     Boolean                            busy;
  37.     UInt32                            flags;                // Flags from StorageClassRequest pb
  38.     UInt32                            currentSGElement;    // Scatter Gather element currently being transferred
  39.     UInt32                            currentSGCount;        // Scatter Gather element currently being transferred
  40.     StorageExecuteCommandPBPtr        userPBPtr;
  41.     StorageClassCompletionProcPtr    completionProc;
  42. };
  43. typedef struct StorageClassTransactionPB    StorageClassTransactionPB;
  44. typedef    StorageClassTransactionPB             *StorageClassTransactionPBPtr;
  45.  
  46. static    StorageClassTransactionPB    gCommandPB;                            // Used only by StorageClassDriverExecuteCommand
  47.  
  48. // Completion routines
  49. static void         ExecuteCommandCompletion(USBPB* usbPB);
  50.  
  51. OSStatus StorageClassCBIAbortCommand( StorageExecuteCommandPBPtr cmdPBPtr )
  52. {
  53.     OSStatus err = noErr;
  54.     
  55.     if (( gCommandPB.busy == true ) && ( cmdPBPtr == gCommandPB.userPBPtr ))
  56.     {
  57.         // If there is a command pending, and the command is the one we want to
  58.         // abort, go ahead and do it.
  59.         USBReference pipeRef;
  60.         
  61.         switch ( gCommandPB.usbPB.usbRefcon )
  62.         {
  63.             case kCBIBulkIOComplete:
  64.             {
  65.                 if (gCommandPB.flags & kStorageDataIn)
  66.                 {
  67.                     pipeRef = GetBulkInPipeRef();
  68.                 }
  69.                 else if (gCommandPB.flags & kStorageDataOut)
  70.                 {
  71.                     pipeRef = GetBulkOutPipeRef();
  72.                 }
  73.                 else
  74.                 {
  75.                     pipeRef = GetInterfaceRef();
  76.                 }
  77.             }
  78.             break;
  79.             
  80.             case kCBIReadInterruptComplete:
  81.             {
  82.                 pipeRef = GetInterruptPipeRef();
  83.             }
  84.             break;
  85.             
  86.             default:
  87.             {
  88.                 pipeRef = GetInterfaceRef();
  89.             }
  90.             break;
  91.         }
  92.  
  93.         err = USBAbortPipeByReference(pipeRef);
  94.     }
  95.     else
  96.     {
  97.         err = abortErr;
  98.     }
  99.  
  100.     return err;
  101. }
  102.  
  103.  
  104. OSStatus StorageClassCBIExecuteCommand( StorageExecuteCommandPBPtr cmdPBPtr )
  105. {
  106.     OSStatus            myErr;
  107.     
  108.     // check if we already have a read in progress, if so return error.
  109.     if (gCommandPB.busy == true)
  110.     {
  111.         return kCommandBusyError;
  112.     }
  113.     
  114.     BlockZero(&gCommandPB, sizeof(StorageClassTransactionPB));
  115.     gCommandPB.busy = true;
  116.  
  117.     InitParamBlock( GetInterfaceRef(), &gCommandPB.usbPB);
  118.     
  119.     // Get a local copy of the callers cdb
  120.     BlockCopy(&cmdPBPtr->cdb[0], &gCommandPB.cdb[0], kUSBStorageMaxCDBSize);
  121.     
  122.     gCommandPB.flags = cmdPBPtr->flags;
  123.     gCommandPB.userPBPtr = (StorageExecuteCommandPBPtr) cmdPBPtr;                // Save the ptr to the callers PB
  124.     
  125.     // Make sure that the AutoSenseIsValid field is set to false so if we don't get the status, the client doesn't think we did
  126.     cmdPBPtr->autoStatusIsValid = false;
  127.  
  128.     gCommandPB.usbPB.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface);            
  129.     gCommandPB.usbPB.usb.cntl.BRequest         = 0;
  130.     gCommandPB.usbPB.usb.cntl.WValue         = 0;
  131.     gCommandPB.usbPB.usb.cntl.WIndex         = 0;
  132.     
  133.     gCommandPB.usbPB.usbBuffer                 = (Ptr)&gCommandPB.cdb[0];
  134.     gCommandPB.usbPB.usbReqCount             = kUSBStorageMaxCDBSize;
  135.     gCommandPB.usbPB.usbFlags                 = kUSBNo5SecTimeout;
  136.     
  137.     gCommandPB.usbPB.usbRefcon                 = kCBIExecuteCommand;
  138.     gCommandPB.usbPB.usbCompletion             = (USBCompletion)ExecuteCommandCompletion;
  139.         
  140.     myErr = USBDeviceRequest(&gCommandPB.usbPB);
  141.     if (myErr != kRequestPending )
  142.     {
  143.         // The command completed immediately ( we probably got an error )
  144.         // clear the PB's busy flag and return
  145.         gCommandPB.busy = false;
  146.     }
  147.  
  148.     cmdPBPtr->status = myErr;
  149.     return myErr;
  150. }
  151.  
  152.  
  153. void ExecuteCommandCompletion(USBPB* usbPB)
  154. {
  155.     StorageClassTransactionPBPtr    transPtr;
  156.     StorageExecuteCommandPBPtr        cmdPBPtr;
  157.  
  158.     transPtr = (StorageClassTransactionPBPtr) usbPB;
  159.     
  160.     // Retrieve the callers pb
  161.     cmdPBPtr = (StorageExecuteCommandPBPtr) transPtr->userPBPtr;
  162.     
  163.     switch(usbPB->usbRefcon)
  164.     {
  165.         case kCBIExecuteCommand:        // Device request completion
  166.         {
  167.             // First check to see if an error occurred on the command out
  168.             if (usbPB->usbStatus != noErr)
  169.             {
  170.                 cmdPBPtr->status = GetStatusEndpointStatus( usbPB, GetInterfaceRef(), ExecuteCommandCompletion, (Ptr) transPtr->GetStatusBuffer, kCBIGetStatusControlEndpointComplete);
  171.             }
  172.             else
  173.             {
  174.                 // If there is to be no data transfer then we are done and can return to the caller
  175.                 // We will only get to here if no Error occurred.
  176.                 if (transPtr->flags & kStorageNoData)
  177.                 {
  178.                     cmdPBPtr->status = noErr;
  179.                     break;
  180.                 }
  181.  
  182.                 // Setup the usb pb for either bulk in or out
  183.                 if (transPtr->flags & kStorageDataIn)
  184.                 {
  185.                     InitParamBlock( GetBulkInPipeRef(), usbPB);
  186.                 }
  187.                 else if (transPtr->flags & kStorageDataOut)
  188.                 {
  189.                     InitParamBlock( GetBulkOutPipeRef(), usbPB);
  190.                 }
  191.         
  192.                 if (transPtr->flags & kStorageSGBuffer)
  193.                 {
  194.                     // We have a scatter-gather transfer 
  195.                     USBSGListPtr        theSGList;
  196.                     USBSGElementPtr        currentSGElement;
  197.                     
  198.                     transPtr->currentSGElement = 0;
  199.                     transPtr->currentSGCount = 0;
  200.                     theSGList = (USBSGListPtr) cmdPBPtr->userBuffer;
  201.                     currentSGElement = &theSGList->sgElementList[0];
  202.                     if ( currentSGElement->SGCount > kUSBMaxBulkTransfer )
  203.                     {
  204.                         usbPB->usbReqCount     = kUSBMaxBulkTransfer;
  205.                     }
  206.                     else
  207.                     {
  208.                         usbPB->usbReqCount     = currentSGElement->SGCount;
  209.                     }
  210.                     
  211.                     usbPB->usbBuffer         = currentSGElement->SGAddr;
  212.                 }
  213.                 else
  214.                 {
  215.                     // We have a single buffer transfer 
  216.                     if ( cmdPBPtr->expectedCount > kUSBMaxBulkTransfer )
  217.                     {
  218.                         usbPB->usbReqCount     = kUSBMaxBulkTransfer;
  219.                     }
  220.                     else
  221.                     {
  222.                         usbPB->usbReqCount     = cmdPBPtr->expectedCount;
  223.                     }
  224.                     
  225.                     usbPB->usbBuffer         = cmdPBPtr->userBuffer;
  226.                 }
  227.  
  228.                 usbPB->usbRefcon         = kCBIBulkIOComplete;
  229.                 usbPB->usbActCount        = 0;
  230.                 usbPB->usbCompletion     = (USBCompletion)ExecuteCommandCompletion;
  231.  
  232.                 // Start a bulk in or out transaction
  233.                 if (transPtr->flags & kStorageDataIn)
  234.                 {
  235.                     cmdPBPtr->status = USBBulkRead(&transPtr->usbPB);
  236.                 }
  237.                 else if (transPtr->flags & kStorageDataOut)
  238.                 {
  239.                     cmdPBPtr->status = USBBulkWrite(&transPtr->usbPB);
  240.                 }
  241.             }
  242.         }
  243.         break;
  244.         
  245.         case kCBIBulkIOComplete:
  246.         {
  247.             cmdPBPtr->actualCount += usbPB->usbActCount;            // Update the users byte count
  248.             
  249.             if (usbPB->usbStatus != noErr)
  250.             {
  251.                 // Either an error occurred on transfer or we did not get all the data we requested.
  252.                 // In either case, this transfer is complete, clean up and return an error to the client.
  253.                 if (GetInterfaceSubclass() == kUSBStorageSFF8070iSubclass )
  254.                 {
  255.                     InitParamBlock( GetInterruptPipeRef(), usbPB);     // Read the Status from the interrupt
  256.         
  257.                     usbPB->usbBuffer         = (Ptr)cmdPBPtr->autoStatus;
  258.                     usbPB->usbReqCount         = kUSBStorageAutoStatusSize;
  259.                     usbPB->usbCompletion     = (USBCompletion)ExecuteCommandCompletion;
  260.                     usbPB->usbRefcon         = kCBIReadInterruptComplete;
  261.                 
  262.                     cmdPBPtr->status = USBIntRead( usbPB );
  263.                 }
  264.                 //else if (GetInterfaceSubclass() == kUSBStorageUFISubclass)
  265.                 else
  266.                 {
  267.                     cmdPBPtr->status = GetStatusEndpointStatus( usbPB, GetInterfaceRef(), ExecuteCommandCompletion,(Ptr) transPtr->GetStatusBuffer, kCBIGetStatusControlEndpointComplete);
  268.                 }
  269.             }
  270.             else if (( cmdPBPtr->actualCount != cmdPBPtr->expectedCount) && ( usbPB->usbActCount == usbPB->usbReqCount ))
  271.             {
  272.                 // If we have not yet transfered all the data and there are no Errors and we did not receive a short packet.
  273.                 // Setup the usb pb for either bulk in or out
  274.                 UInt32 actCount = usbPB->usbActCount;
  275.                 
  276.                 if (transPtr->flags & kStorageDataIn)
  277.                 {
  278.                     InitParamBlock( GetBulkInPipeRef(), usbPB);
  279.                 }
  280.                 else if (transPtr->flags & kStorageDataOut)
  281.                 {
  282.                     InitParamBlock( GetBulkOutPipeRef(), usbPB);
  283.                 }
  284.     
  285.                 if (transPtr->flags & kStorageSGBuffer)
  286.                 {
  287.                     // We have a scatter-gather transfer 
  288.                     USBSGListPtr        theSGList;
  289.                     USBSGElementPtr        currentSGElement;
  290.                     
  291.                     transPtr->currentSGCount += actCount;
  292.                     theSGList = (USBSGListPtr) cmdPBPtr->userBuffer;
  293.                     currentSGElement = &theSGList->sgElementList[transPtr->currentSGElement];
  294.                     
  295.                     if ( transPtr->currentSGCount >= currentSGElement->SGCount)
  296.                     {
  297.                         // Move on to next SG segment
  298.                         transPtr->currentSGElement++;
  299.                         currentSGElement = &theSGList->sgElementList[transPtr->currentSGElement];
  300.                         transPtr->currentSGCount = 0;
  301.                         if ( currentSGElement->SGCount > kUSBMaxBulkTransfer )
  302.                         {
  303.                             usbPB->usbReqCount     = kUSBMaxBulkTransfer;
  304.                         }
  305.                         else
  306.                         {
  307.                             usbPB->usbReqCount     = currentSGElement->SGCount;
  308.                         }
  309.                         
  310.                         usbPB->usbBuffer         = currentSGElement->SGAddr;
  311.                     }
  312.                     else
  313.                     {
  314.                         if ( (currentSGElement->SGCount - transPtr->currentSGCount) > kUSBMaxBulkTransfer )
  315.                         {
  316.                             usbPB->usbReqCount     = kUSBMaxBulkTransfer;
  317.                         }
  318.                         else
  319.                         {
  320.                             usbPB->usbReqCount     = (currentSGElement->SGCount - transPtr->currentSGCount);
  321.                         }
  322.                         
  323.                         usbPB->usbBuffer         = currentSGElement->SGAddr + transPtr->currentSGCount;
  324.                     }
  325.                 }
  326.                 else
  327.                 {
  328.                     if ( (cmdPBPtr->expectedCount - cmdPBPtr->actualCount) > kUSBMaxBulkTransfer )
  329.                     {
  330.                         usbPB->usbReqCount     = kUSBMaxBulkTransfer;
  331.                     }
  332.                     else
  333.                     {
  334.                         usbPB->usbReqCount     = (cmdPBPtr->expectedCount - cmdPBPtr->actualCount);
  335.                     }
  336.                     
  337.                     usbPB->usbBuffer         = (cmdPBPtr->userBuffer) + (cmdPBPtr->actualCount);
  338.                 }
  339.                 
  340.                 usbPB->usbRefcon         = kCBIBulkIOComplete;
  341.                 usbPB->usbActCount        = 0;
  342.                 usbPB->usbCompletion     = (USBCompletion)ExecuteCommandCompletion;
  343.  
  344.                  // Continue a bulk in or out transaction
  345.                 if (transPtr->flags & kStorageDataIn)
  346.                 {
  347.                     cmdPBPtr->status = USBBulkRead(&transPtr->usbPB);
  348.                 }
  349.                 else if (transPtr->flags & kStorageDataOut)
  350.                 {
  351.                     cmdPBPtr->status = USBBulkWrite(&transPtr->usbPB);
  352.                 }
  353.             }
  354.             else
  355.             {
  356.                 if (( GetInterruptPipeRef() != 0 ) && (transPtr->flags & kStorageUseCommandCompletionInt))
  357.                 {
  358.                     // We have an interrupt pipe, and device uses it to determine a command is done
  359.                     InitParamBlock( GetInterruptPipeRef(), usbPB);     
  360.         
  361.                     usbPB->usbBuffer         = (Ptr)cmdPBPtr->autoStatus;
  362.                     usbPB->usbReqCount         = kUSBStorageAutoStatusSize;
  363.                     usbPB->usbCompletion     = (USBCompletion)ExecuteCommandCompletion;
  364.                     usbPB->usbRefcon         = kCBIReadInterruptComplete;
  365.                 
  366.                     cmdPBPtr->status = USBIntRead( usbPB );    // Read the Status from the interrupt
  367.                 }
  368.                 else
  369.                 {
  370.                     cmdPBPtr->status = noErr;
  371.                 }
  372.             }
  373.         }
  374.         break;
  375.  
  376.         case kCBIReadInterruptComplete:
  377.         {
  378.             // What should the status really be, should probably process and return
  379.             // a relevent error.
  380.             if ((usbPB->usbStatus == noErr) && ((GetInterfaceSubclass() == kUSBStorageSFF8070iSubclass ) || ( GetInterfaceSubclass() == kUSBStorageUFISubclass )))
  381.             {
  382.                 cmdPBPtr->autoStatusIsValid = true;
  383.  
  384.                 // Decide what error to return based on the Interrupt data
  385.                 if (( cmdPBPtr->autoStatus[0] == 0x00 ) && ( cmdPBPtr->autoStatus[1] == 0x00 ))
  386.                 {
  387.                     cmdPBPtr->status = noErr;
  388.                 }
  389.                 else
  390.                 {
  391.                     cmdPBPtr->status = kUSBInternalErr;
  392.                 }
  393.             }
  394.             else
  395.             {
  396.                 // The Class doesn't know how to interpret the data
  397.                 // return an error and mark interrupt data as invalid
  398.                 cmdPBPtr->autoStatusIsValid = false;
  399.                 cmdPBPtr->status = kUSBInternalErr;
  400.             }
  401.         }
  402.         break;
  403.  
  404.         case kCBIGetStatusControlEndpointComplete:
  405.         {
  406.             if (usbPB->usbStatus == noErr)
  407.             {
  408.                 if (((transPtr->GetStatusBuffer[0] & 1) == 1 ) || (GetInterfaceSubclass() == kUSBStorageUFISubclass))
  409.                 {
  410.                     // This endpoint was stalled, go ahead and clear it
  411.                     cmdPBPtr->status = ClearFeatureEndpointStall( usbPB, GetInterfaceRef(), ExecuteCommandCompletion, kCBIClearControlEndpointComplete);
  412.                 }
  413.                 else
  414.                 {
  415.                     if ( transPtr->flags & kStorageNoData )
  416.                     {
  417.                         cmdPBPtr->actualCount =    0;
  418.                         cmdPBPtr->status = kUSBInternalErr;
  419.                     }
  420.                     else
  421.                     {
  422.                         // Check if the bulk endpoint was stalled
  423.                         USBPipeRef pipeRef = 0;
  424.                         
  425.                         if (transPtr->flags & kStorageDataIn)
  426.                         {
  427.                             pipeRef = GetBulkInPipeRef();
  428.                         }
  429.                         else if (transPtr->flags & kStorageDataOut)
  430.                         {
  431.                             pipeRef = GetBulkOutPipeRef();
  432.                         }
  433.                         else
  434.                         {
  435.                             pipeRef = GetInterfaceRef();
  436.                         }
  437.                         
  438.                         cmdPBPtr->status = GetStatusEndpointStatus( usbPB, pipeRef, ExecuteCommandCompletion,(Ptr) transPtr->GetStatusBuffer, kCBIGetStatusBulkEndpointComplete);
  439.                     }
  440.                 }
  441.             }
  442.             else
  443.             {
  444.                 // An error occurred to GET_STATUS ( shouldn't happen!!) reset the endpoint anyway
  445.                 cmdPBPtr->status = ClearFeatureEndpointStall( usbPB, GetInterfaceRef(), ExecuteCommandCompletion, kCBIClearControlEndpointComplete);
  446.             }
  447.         }
  448.         break;
  449.         
  450.         case kCBIClearControlEndpointComplete:
  451.         {
  452.             if (usbPB->usbStatus == noErr)
  453.             {
  454.                 if ( transPtr->flags & kStorageNoData )
  455.                 {
  456.                     cmdPBPtr->actualCount =    0;
  457.                     cmdPBPtr->status = kUSBInternalErr;
  458.                 }
  459.                 else
  460.                 {
  461.                     // Check if the bulk endpoint was stalled
  462.                     USBPipeRef pipeRef = 0;
  463.                     
  464.                     if (transPtr->flags & kStorageDataIn)
  465.                     {
  466.                         pipeRef = GetBulkInPipeRef();
  467.                     }
  468.                     else if (transPtr->flags & kStorageDataOut)
  469.                     {
  470.                         pipeRef = GetBulkOutPipeRef();
  471.                     }
  472.                     else
  473.                     {
  474.                         pipeRef = GetInterfaceRef();
  475.                     }
  476.                     
  477.                     cmdPBPtr->status = GetStatusEndpointStatus( usbPB, pipeRef, ExecuteCommandCompletion,(Ptr) transPtr->GetStatusBuffer, kCBIGetStatusBulkEndpointComplete);
  478.                 }
  479.             }
  480.             else
  481.             {
  482.                 cmdPBPtr->status = usbPB->usbStatus;
  483.             }
  484.         }
  485.         break;
  486.         
  487.         case kCBIGetStatusBulkEndpointComplete:
  488.         {
  489.             if (usbPB->usbStatus == noErr)
  490.             {
  491.                 if (( (transPtr->GetStatusBuffer[0] & 1) == 1 ) || (GetInterfaceSubclass() == kUSBStorageUFISubclass))
  492.                 {
  493.                     USBPipeRef pipeRef = 0;
  494.                     
  495.                     if (transPtr->flags & kStorageDataIn)
  496.                     {
  497.                         pipeRef = GetBulkInPipeRef();
  498.                     }
  499.                     else if (transPtr->flags & kStorageDataOut)
  500.                     {
  501.                         pipeRef = GetBulkOutPipeRef();
  502.                     }
  503.                     else
  504.                     {
  505.                         pipeRef = GetInterfaceRef();
  506.                     }
  507.                     
  508.                     cmdPBPtr->status = ClearFeatureEndpointStall( usbPB, pipeRef, ExecuteCommandCompletion, kCBIClearBulkEndpointComplete);
  509.                 }
  510.                 else
  511.                 {
  512.                     cmdPBPtr->actualCount =    0;
  513.                     cmdPBPtr->status = kUSBInternalErr;
  514.                 }
  515.             }
  516.             else
  517.             {
  518.                 USBPipeRef pipeRef = 0;
  519.                 
  520.                 if (transPtr->flags & kStorageDataIn)
  521.                 {
  522.                     pipeRef = GetBulkInPipeRef();
  523.                 }
  524.                 else if (transPtr->flags & kStorageDataOut)
  525.                 {
  526.                     pipeRef = GetBulkOutPipeRef();
  527.                 }
  528.                 else
  529.                 {
  530.                     pipeRef = GetInterfaceRef();
  531.                 }
  532.                     
  533.                 cmdPBPtr->status = ClearFeatureEndpointStall( usbPB, pipeRef, ExecuteCommandCompletion, kCBIClearBulkEndpointComplete);
  534.             }
  535.         }
  536.         break;
  537.  
  538.         case kCBIClearBulkEndpointComplete:
  539.         {
  540.             cmdPBPtr->actualCount =    0;
  541.             cmdPBPtr->status = kUSBInternalErr;
  542.         }
  543.         break;
  544.         
  545.         default:
  546.         {
  547.             cmdPBPtr->actualCount =    0;
  548.             cmdPBPtr->status = kUSBInternalErr;
  549.         }
  550.         break;
  551.     }
  552.  
  553.     // If the command has been completed ( no longer pending ), call the clients completion routine.    
  554.     if (cmdPBPtr->status != kRequestPending )
  555.     {
  556.         BlockZero ( usbPB, sizeof(USBPB));
  557.         transPtr->busy = false;
  558.         if(cmdPBPtr->completionProc != nil)
  559.         {
  560.             (*cmdPBPtr->completionProc)((StorageExecuteCommandPBPtr) cmdPBPtr);
  561.         }
  562.     }
  563. }
  564.  
  565.